<?php
/**
 * Created by PhpStorm.
 * User: tian
 * Date: 17-12-11
 * Time: 下午10:28
 * 用于上传表格的格式验证
 */

namespace app\common\commonClass;
use PHPExcel_IOFactory;
use think\Exception;

class ExcelImportTool
{
    /*初始化后的实例*/
    protected static $instance;

    /*解析后的表格数据*/
    protected $dataArr=[];

    /*标题数组*/
    protected $headerArr=[];

    //数据结构
    protected $construct=[];

    //结果数组
    protected $result=[];

    /*标题定位数组*/
    protected $arr_pos=[];

    /*一级标题缓存*/
    protected $temp=null;

    protected $arr_index_deep=[];
    protected $arr_index_simple=[];

    /*构造函数*/
    public function __construct($path)
    {
        $this->dataArr=self::read_excel($path);
    }

    /*初始化*/
    public static function instance($path)
    {
        if (is_null(self::$instance)){
            self::$instance=new static($path);
        }
        return self::$instance;
    }

    /*设置标题数据*/
    public function header(array $headerArr,$construct=[])
    {
        $this->headerArr=$headerArr;
        $this->construct=$construct;
        return $this;
    }

    /**
     * @param array $arr_require_always
     * @param array $arr_require_once
     * @return ExcelImportTool
     * @throws \Exception
     * 验证数据
     */
    public function check(array $arr_require_always,array $arr_require_once=[])
    {
        $flippedHeader=array_flip($this->headerArr);
        foreach ($this->dataArr[1] as $pos=> $headerText) {//获取每列标题的条目位置
            if (in_array($headerText,$this->headerArr)){
                $this->arr_pos[$flippedHeader[$headerText]]=$pos;
            }
        }

        foreach ($this->headerArr as $headerText){//验证模板数据完整性
            if (!in_array($headerText,$this->dataArr[1])){
                throw new Exception('数据不完整！缺少列：'.$headerText);
            }
        }

        foreach ($this->dataArr as $index=> $line){//遍历数据存入数组
            if ($index==2){//验证首行非空数据
                foreach ($arr_require_once as $item_require) {
                    if (!isset($line[$this->arr_pos[$item_require]])){
                        throw new Exception('第2行中缺少'.$flippedHeader[$item_require].'值');
                    }
                }
            }
            foreach ($arr_require_always as $item_require) {//验证每行必须的数据
                if (!isset($line[$this->arr_pos[$item_require]])){
                    throw new Exception('第'.$index.'行中缺少'.$flippedHeader[$item_require].'值');
                }
            }
        }
        return $this;
    }

    /**
     * @param array $content 要加入的内容
     * @param array $target 要加入到的目标数组
     */
    protected function appendToArray(array $content,array &$target)
    {
        foreach ($content as $key=>$val) {
            if (!is_array($val)){
                if(!isset($target[$key])){$target[$key]=$val;}
            }else{
                if(!isset($target[$key])){$target[$key]=[];}
                $this->appendToArray($val,$target[$key]);
            }
        }
    }

    /**
     * @param array $construct 要完成的数组结构，如：['name'=> ['marker'=>['mut'=>'mutation','allele'=>'frequency']]]
     * @param array $data 原始数据，一维数组
     * @param array $target 目标数组
     * @return array
     */
    protected function makeArray($construct,$data,$target){
        foreach ($construct as $key=>$val) {
            if (!is_array($val)){
                if ($key==$val){
                    $target[$key]=$data[$val];
                }else{
                    $index=isset($data[$key]) ? $data[$key] :$key;
                    $target[$index]=$data[$val];
                }
            }else{
                $target[$data[$key]]=$this->makeArray($val,$data,$target);
            }
        }
        return $target;
    }

    /**
     * @return array
     * 数据存入数组
     */
    public function toArray()
    {
        foreach ($this->dataArr as $num=> $line) {
            if ($num == 1) continue;//跳过第一行
            $data = [];
            foreach (array_keys($this->headerArr) as $header) {
                $data[$header] = $line[$this->arr_pos[$header]];
            }
            $result=$this->makeArray($this->construct,$data,[]);
            $this->appendToArray($result,$this->result);
        }
        return $this->result;
    }

    public function toSimpleArray()
    {
        $result = [];
        foreach ($this->dataArr as $num=> $line) {
            if ($num == 1) continue;//跳过第一行
            $data = [];
            foreach (array_keys($this->headerArr) as $header) {
                $data[$header] = $line[$this->arr_pos[$header]];
            }
            $result[] = $data;
        }
        return $result;
    }

    /**
     *
     */
    public function originalData()
    {
        $data = [];
        $index = 0;
        foreach ($this->dataArr as $num => $line) {
            if ($num == 1) continue;//跳过第一行
            foreach (array_keys($this->headerArr) as $header) {
                $data[$index][$header] = $line[$this->arr_pos[$header]];
            }
            $index++;
        }
        return $data;
    }

    /**
     * @param string $path
     * @return array
     * @throws \Exception
     */
    //读取excel返回数组
    static public function read_excel($path)
    {
        self::checkPath($path);

        $info = pathinfo($path);
        $type=$info['extension'];
        if($type=='xlsx'||$type=='xls' ){
            $reader = PHPExcel_IOFactory::createReader('Excel2007'); // 读取 excel 文档
        }else if( $type=='csv' ){
            $reader = PHPExcel_IOFactory::createReader('CSV'); // 读取 csv 文档
        }else{
            die('Not supported file types!');
        }
        //载入文件
        $PHPExcel = $reader->load($path);
        //获取表中的第一个工作表，如果要获取第二个，把0改为1，依次类推
        $currentSheet = $PHPExcel->getSheet(0);
        //获取总列数
        $allColumn = $currentSheet->getHighestColumn();
        //获取总行数
        $allRow = $currentSheet->getHighestRow();
        //循环获取表中的数据，$currentRow表示当前行，从哪行开始读取数据，索引值从0开始
        for ($currentRow = 1; $currentRow <= $allRow; $currentRow++) {
            //从哪列开始，A表示第一列
            for ($currentColumn = 'A'; $currentColumn <= $allColumn; $currentColumn++) {
                //数据坐标
                $address = $currentColumn . $currentRow;
                //读取到的数据，保存到数组$arr中
                $data[$currentRow][$currentColumn] = $currentSheet->getCell($address)->getValue();
            }
        }
        return $data;
    }

    //二维数组转成一维数组
    protected function changeArray($arr)
    {
        foreach ($arr as $key1=>$item1) {
            if (is_array($item1)){
                $this->arr_index_deep[]=$key1;
                foreach ($item1 as $key2=>$item2) {
                    $key=$key1.'/'.$key2;
                    $arr[$key]=$item2;
                }
                unset($arr[$key1]);
            }else{//设置缓存
                $this->arr_index_simple[]=$key1;
                $this->temp[$key1]=null;
            }
        }
        return $arr;
    }

    //校验路径
    static public function checkPath($path)
    {
        if (!file_exists($path)){
            throw new Exception('ExcelImport.PHP->__construct:file dose not exist!');
        }
    }


}